<?php


use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Lcobucci\Clock\SystemClock;
use Lcobucci\JWT\Validation\Constraint\IssuedBy;
use Lcobucci\JWT\Validation\Constraint\PermittedFor;
use Lcobucci\JWT\Validation\Constraint\SignedWith;

class JwtHelper
{
    private $config;
    private $clock;

    public function __construct($secretKey)
    {
        $this->config = Configuration::forSymmetricSigner(
            new Sha256(),
            InMemory::base64Encoded($secretKey)
        );
        $this->clock = SystemClock::fromSystemTimezone();
    }

    public function createToken($issuer, $audience, $id, $claims = [], $expirationMinutes = 60, $notBeforeMinutes = 1)
    {
        $now = $this->clock->now();
        $builder = $this->config->builder()
            ->issuedBy($issuer)
            ->permittedFor($audience)
            ->identifiedBy($id)
            ->issuedAt($now)
            ->canOnlyBeUsedAfter($now->modify("+{$notBeforeMinutes} minute"))
            ->expiresAt($now->modify("+{$expirationMinutes} minute"));

        foreach ($claims as $key => $value) {
            $builder->withClaim($key, $value);
        }

        $token = $builder->getToken($this->config->signer(), $this->config->signingKey());
        return $token->toString();
    }

    public function validateToken($jwt, $issuer, $audience)
    {
        try {
            $token = $this->config->parser()->parse($jwt);

            $constraints = [
                new IssuedBy($issuer),
                new PermittedFor($audience),
                new SignedWith($this->config->signer(), $this->config->signingKey())
            ];

            return $this->config->validator()->validate($token, ...$constraints);
        } catch (\Exception $e) {
            return false;
        }
    }

    public function getClaims($jwt)
    {
        try {
            $token = $this->config->parser()->parse($jwt);
            return $token->claims();
        } catch (\Exception $e) {
            return null;
        }
    }
}